package com.remote.client;

import com.remote.common.RemoteFactory;
import com.remote.common.command.Commands;
import com.remote.common.command.handler.CommandContext;
import com.remote.common.context.RemoteContext;
import com.remote.common.context.listener.CloseListener;
import com.remote.common.context.listener.ConnectListener;
import com.remote.common.context.listener.ReadListener;
import com.remote.common.model.ClientInfo;
import com.remote.common.model.Request;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;

public class ClientCommandContext implements CommandContext {

    private RemoteContext remoteContext;
    private ClientInfo currentClient;
    private static ChannelHandlerContext context;

    private final static ArrayBlockingQueue<Request> AEND_QUEUE = new ArrayBlockingQueue<>(100);
    private final static Logger LOGGER = LoggerFactory.getLogger(ClientCommandContext.class);

    public ClientCommandContext(RemoteContext remoteContext) {
        this.remoteContext = remoteContext;
    }

    private Runnable task = new Runnable() {
        @Override
        public void run() {
            Request request = null;
            try {
                while ((request = AEND_QUEUE.take()) != null) {
                    ClientCommandContext.this.writeAndFlush(request);
                }
            } catch (InterruptedException e) {
                LOGGER.error(e.getMessage(), e);
            }

        }
    };

    @Override
    public void setContext(ChannelHandlerContext context) {
        ClientCommandContext.context = context;
    }

    @Override
    public void setClient(ClientInfo clientInfo) {
        this.currentClient = clientInfo;
    }

    @Override
    public void fireCommand(String targetClientId, Commands commands, Object value) {
        Request request = new Request();
        request.setTargetClientId(targetClientId);
        request.setClientId(getClient().getClientId());
        request.setCommand(commands);
        request.setValue(value);
        AEND_QUEUE.offer(request);
    }

    @Override
    public void fireCommand(Request request) {
        AEND_QUEUE.offer(request);
    }

    private void writeAndFlush(Request request) {
        context.writeAndFlush(request);
    }

    @Override
    public ClientInfo getClient() {
        return currentClient;
    }


    @Override
    public void addConnectListener(ConnectListener connectListener) {
        remoteContext.addConnectListener(connectListener);
    }

    @Override
    public void addCloseListener(CloseListener closeListener) {
        remoteContext.addCloseListener(closeListener);
    }

    @Override
    public void addReadListener(ReadListener<?> readListener) {
        remoteContext.addReadListener(readListener);
    }

    @Override
    public void setChannelInitializer(ChannelInitializer<SocketChannel> channelInitializer) {
        remoteContext.setChannelInitializer(channelInitializer);
    }

    @Override
    public Channel connect() {
        Channel connect = remoteContext.connect();
        new Thread(task).start();
        return connect;
    }


    @Override
    public List<ConnectListener> getConnectListeners() {
        return remoteContext.getConnectListeners();
    }

    @Override
    public void close() {
        remoteContext.close();
    }

    @Override
    public void refresh() {
        remoteContext.refresh();
    }

    @Override
    public RemoteFactory getRemoteFactory() {
        return remoteContext.getRemoteFactory();
    }

    @Override
    public List<CloseListener> getCloseListeners() {
        return remoteContext.getCloseListeners();
    }

    @Override
    public List<ReadListener> getReadListeners() {
        return remoteContext.getReadListeners();
    }

}
